package net.cyue.web.easyquery.core;

import net.cyue.util.ResourceUtil;
import net.cyue.util.StringUtil;
import net.cyue.web.easyquery.core.config.*;
import net.cyue.web.easyquery.core.config.json.EasyQueryJSONConfiguration;
import net.cyue.web.easyquery.core.config.toml.EasyQueryTOMLConfiguration;
import net.cyue.web.easyquery.core.db.QueryType;
import net.cyue.web.easyquery.core.http.data.PathInfo;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.io.InputStream;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.Map;
import java.util.Properties;

public class EasyQueryConfigurationLoader {

    private final Logger logger = LoggerFactory.getLogger(this.toString());
    private final EasyQueryContext<?> context;
    private EasyQueryConfiguration configuration = new EasyQueryConfiguration();

    public EasyQueryConfigurationLoader(EasyQueryContext<?> context) {
        this.context = context;
        try {
            this.load(this.configuration);
        } catch (ConfigException e) {
            this.logger.warn(e.getMessage(), e);
        }
    }

    private void logConfigItemInfo() {
        if (this.configuration == null) {
            return;
        }

        // 打印信息
        StringBuilder sb = new StringBuilder("\n附加配置项：");
        for (AdditionalConfigItem item : this.configuration.getAdditionalConfigurationHandlerMap().keySet()) {
            sb.append("\n\t").append(item.getFullName());
        }
        this.logger.info(sb.toString());
    }

    public void loadResource(String resourceName) throws IOException, ConfigException {
        if (!resourceName.contains(".") || resourceName.endsWith("/")) {
            throw new IllegalArgumentException("Unsupported configuration type: " + resourceName);
        }

        try (InputStream is = ResourceUtil.getResourceAsStream(resourceName)) {
            String lowCaseResourceName = resourceName.toLowerCase();
            if (lowCaseResourceName.endsWith(".properties")) {
                this.loadProperties(is);
            } else if (lowCaseResourceName.endsWith(".json")) {
                this.load(EasyQueryJSONConfiguration.fromStream(is));
            } else if (lowCaseResourceName.endsWith(".toml")) {
                this.load(EasyQueryTOMLConfiguration.fromStream(is));
            } else {
                throw new IllegalArgumentException("Unsupported configuration type: " + resourceName);
            }
        }
    }

    public void loadProperties(InputStream is) throws IOException, ConfigException {
        Properties properties = new Properties();
        properties.load(is);
        this.loadProperties(properties);
    }
    public void loadProperties(Properties properties) throws ConfigException {
        this.logConfigItemInfo();
        Enumeration<?> keyEnumeration = properties.propertyNames();
        Map<PathInfo, String> pathQueryMap = new HashMap<>();
        Map<AdditionalConfigItem, Boolean> configItemHandledMap = new HashMap<>(); // 处理过的配置项
        while (keyEnumeration.hasMoreElements()) {
            String key = (String) keyEnumeration.nextElement();
            // 附加配置项
            boolean isConfigItem = false;
            for (Map.Entry<AdditionalConfigItem, IAdditionalConfigItemHandler> entry : this.configuration.getAdditionalConfigurationHandlerMap().entrySet()) {
                AdditionalConfigItem additionalConfigItem = entry.getKey();
                IAdditionalConfigItemHandler handler = entry.getValue();

                // 跳过处理过的
                if (configItemHandledMap.getOrDefault(additionalConfigItem, false)) {
                    continue;
                }

                if (additionalConfigItem.equals(key)) {
                    if (handler == null) {
                        throw new ConfigException("Invalid config item: " + additionalConfigItem.getFullName());
                    }
                    this.logger.info("处理配置项：{}", additionalConfigItem.getFullName());
                    isConfigItem = true;
                    configItemHandledMap.put(additionalConfigItem, true);
                    handler.handle(this.context, additionalConfigItem, properties.getProperty(key));
                    break;
                }
            }
            if (isConfigItem) {
                continue;
            }

            // 默认查询配置项
            String sql = properties.getProperty(key);
            if (StringUtil.isBlank(key) || StringUtil.isBlank(sql)) {
                continue;
            }
            if (sql.startsWith("\"")) {
                sql = sql.substring(1, sql.length() - 1);
            }
            if (sql.endsWith("\"")) {
                sql = sql.substring(0, sql.length() - 1);
            }
            if (sql.startsWith("'")) {
                sql = sql.substring(1, sql.length() - 1);
            }
            if (sql.endsWith("'")) {
                sql = sql.substring(0, sql.length() - 1);
            }

            PathInfo pathInfo = PathInfo.fromAPIPath(key.replace('.', '/'));
            pathQueryMap.put(pathInfo, sql);
        }

        for (Map.Entry<PathInfo, String> entry : pathQueryMap.entrySet()) {
            PathInfo pathInfo = entry.getKey();
            String sql = entry.getValue();
            if (this.context.registerWebInterface(pathInfo, sql)) {
                this.logger.info("成功注册 {} 接口 {}", QueryType.QUERY_LIST, pathInfo.getAPIPath());
            } else {
                this.logger.warn("{} 接口 {} 注册失败", QueryType.QUERY_LIST, pathInfo.getAPIPath());
            }
        }
    }

    public void load(EasyQueryConfiguration configuration)
        throws ConfigException
    {
        if (this.configuration == null) {
            this.configuration = new EasyQueryConfiguration();
        }
        this.configuration.merge(configuration);
        Map<AdditionalConfigItem, IAdditionalConfigItemHandler> handlerMap =
                this.configuration.getAdditionalConfigurationHandlerMap();

        this.logConfigItemInfo();
        for (ConfigItemValue item : this.configuration.getConfigItemValues()) {

            if (item.getType() == ConfigItemValue.Type.ADDITIONAL) {
                ConfigItemValue.Additional additional = (ConfigItemValue.Additional) item;
                AdditionalConfigItem additionalConfigItem = additional.toAdditionalConfigItem();

                this.logger.info("处理配置项：{}", additionalConfigItem.getFullName());
                handlerMap.getOrDefault(
                    additionalConfigItem,
                    (_ctx, _ci, value) -> {
                        this.logger.warn("未注册处理器的配置项：{}", additionalConfigItem.getFullName());
                    }
                ).handle(this.context, additionalConfigItem, additional.getValue());

            } else if (item.getType() == ConfigItemValue.Type.API) {
                ConfigItemValue.API api = (ConfigItemValue.API) item;
                for (String path : api.getPaths()) {
                    PathInfo pathInfo = PathInfo.fromAPIPath(
                        path,
                        this.context.getContextPath(),
                        api.getQueryParameterList()
                    );

                    if (
                        this.context.registerWebInterface(
                            pathInfo,
                            api.getPageParameter(),
                            api.getPageSizeParameter(),
                            api.getSQL(),
                            api.getSQLType(),
                            api.getQueryType()
                        )
                    ) {
                        if (api.getPreHandler() != null) {
                            this.context.addRequestPreHandler(pathInfo, api.getPreHandler());
                        }
                        this.logger.info("成功注册 {} 接口 {}", api.getQueryType(), pathInfo.getAPIPath());
                    } else {
                        this.logger.warn("{} 接口 {} 注册失败", api.getQueryType(), pathInfo.getAPIPath());
                    }
                }

            }
        }
    }
}
